﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using BrightIdeasSoftware;
using ROrganizer.Client;
using ROrganizer.UI.Controllers.Core;

namespace ROrganizer.UI.Controllers
{
    internal class ProposalManagerFormController : IModelFilter
    {
        private readonly FastObservableCollection<Proposal> proposals;
        private readonly AsyncWorker worker;
        private HashCredentials credentials;

        public ProposalManagerFormController(Action<Exception> exceptioner = null)
        {
            this.proposals = new FastObservableCollection<Proposal>();
            this.worker = new AsyncWorker(this.OnChanged, exceptioner: exceptioner);
        }

        public event EventHandler Changed;
        private void OnChanged()
        {
            if (this.Changed != null)
                this.Changed(this, EventArgs.Empty);
        }

        public int Progress { get; private set; }
        public FastObservableCollection<Proposal> Proposals
        {
            get { return this.proposals; }
        }

        public bool IsWorking
        {
            get { return this.worker.IsWorking; }
        }

        public bool CanCancel()
        {
            return this.worker.CanStop;
        }

        public void Cancel()
        {
            this.worker.Stop();
        }

        public bool CanRefreshProposals()
        {
            return !this.IsWorking;
        }

        public void RefreshProposals(IWin32Window owner)
        {
            if (this.credentials == null)
                this.credentials = ViewManager.ShowCredentials(owner, allowCreateAccount: false);

            if (credentials != null)
            {
                this.proposals.Clear();
                this.worker.Execute(this.OnRefreshProposalsCallback);
            }
        }

        private void OnRefreshProposalsCallback()
        {
            var hgateway = new HashGateway();
            var igateway = new ImdbGateway();
            var proposals = hgateway.GetProposals(this.credentials);
            var query = from proposal in proposals
                        select new Proposal
                        {
                            Title = String.Empty,
                            User = proposal.User,
                            Hash = proposal.Hash,
                            Link = proposal.Link,
                            Added = proposal.Added,
                            Reference = proposal
                        };

            var index = 1;
            var prepared = query.ToArray();

            this.Progress = 100 * index++ / (proposals.Length + 1);
            prepared.AsParallel().WithDegreeOfParallelism(8).ForAll(proposal =>
            {
                for (int i = 0; i < 3; i++)
                {
                    var info = igateway.Query(proposal.Reference);
                    if (info == null)
                    {
                        Thread.Sleep(TimeSpan.FromSeconds(5));
                        continue;
                    }
                    
                    proposal.Title = info.Title;

                    lock (igateway)
                    {
                        this.Progress = 100 * index++ / (proposals.Length + 1);
                        this.OnChanged();
                    }

                    break;
                }
            });

            this.proposals.AddRange(prepared);
        }

        public bool CanAcceptProposals(Proposal[] proposals)
        {
            return !this.worker.IsWorking
                && proposals.Any()
                && proposals.All(x => !String.IsNullOrEmpty(x.Title));
        }

        public void AcceptProposals(Proposal[] proposals)
        {
            this.worker.Execute(this.OnAcceptProposalsCallback, proposals);
        }

        private void OnAcceptProposalsCallback(Proposal[] proposals)
        {
            var gateway = new HashGateway();
            var index = 1;

            foreach (var proposal in proposals)
            {
                gateway.AcceptProposal(this.credentials, proposal.Reference);
                this.proposals.Remove(proposal);

                this.Progress = 100 * index++ / proposals.Length;
                this.OnChanged();
            }
        }

        public class Proposal
        {
            public string Title { get; set; }
            public string User { get; set; }
            public string Hash { get; set; }
            public string Link { get; set; }
            public DateTime Added { get; set; }

            public HashProposal Reference { get; set; }
        }

        bool IModelFilter.Filter(object modelObject)
        {
            var proposal = modelObject as Proposal;
            return true;
        }
    }
}
